jetcrab\vm\executor/
error_handler.rs

1//! # Execution Error Handler
2//!
3//! Defines all error types that can occur during VM execution and provides
4//! comprehensive error handling capabilities.
5//!
6//! ## Error Categories
7//!
8//! - **Stack Errors**: Underflow, overflow, invalid operations
9//! - **Type Errors**: Invalid type conversions, unsupported operations
10//! - **Runtime Errors**: General execution failures, exceptions
11//! - **Memory Errors**: Heap allocation failures, invalid references
12//! - **Control Flow Errors**: Invalid jumps, function call failures
13//!
14//! ## Error Handling Strategy
15//!
16//! The VM uses a comprehensive error handling strategy:
17//!
18//! 1. **Immediate Detection**: Errors are detected as soon as they occur
19//! 2. **Detailed Information**: Each error contains context about what went wrong
20//! 3. **Recovery Options**: Some errors can be recovered from automatically
21//! 4. **User Feedback**: Clear error messages for debugging
22//!
23//! ## Usage
24//!
25//! ```rust
26//! use jetcrab::vm::executor::error_handler::ExecutionError;
27//!
28//! match some_operation() {
29//!     Ok(result) => println!("Success: {:?}", result),
30//!     Err(ExecutionError::StackUnderflow) => {
31//!         eprintln!("Stack underflow occurred");
32//!     }
33//!     Err(ExecutionError::TypeError(msg)) => {
34//!         eprintln!("Type error: {}", msg);
35//!     }
36//!     Err(e) => eprintln!("Other error: {:?}", e),
37//! }
38//! ```
39
40use std::error::Error;
41use std::fmt;
42
43/// Represents all possible errors that can occur during VM execution
44///
45/// This enum provides a comprehensive set of error types covering
46/// all aspects of virtual machine operation.
47#[derive(Debug, Clone)]
48pub enum ExecutionError {
49    /// Stack is empty when trying to pop a value
50    StackUnderflow,
51    
52    /// Stack is full when trying to push a value
53    StackOverflow,
54    
55    /// Invalid type conversion or operation
56    TypeError(String),
57    
58    /// General runtime execution error
59    RuntimeError(String),
60    
61    /// Invalid memory access or allocation failure
62    MemoryError(String),
63    
64    /// Invalid instruction or bytecode
65    InvalidInstruction(String),
66    
67    /// Function call or return error
68    FunctionError(String),
69    
70    /// Variable access or assignment error
71    VariableError(String),
72    
73    /// Heap allocation or garbage collection error
74    HeapError(String),
75    
76    /// Control flow error (invalid jumps, etc.)
77    ControlFlowError(String),
78    
79    /// Built-in function error
80    BuiltinError(String),
81    
82    /// Division by zero
83    DivisionByZero,
84    
85    /// Invalid array index
86    InvalidIndex(usize),
87    
88    /// Property not found on object
89    PropertyNotFound(String),
90    
91    /// Method not found on object
92    MethodNotFound(String),
93    
94    /// Invalid argument count for function call
95    InvalidArgumentCount {
96        expected: usize,
97        received: usize,
98    },
99    
100    /// Recursion limit exceeded
101    RecursionLimitExceeded(usize),
102    
103    /// Timeout during execution
104    ExecutionTimeout,
105    
106    /// Unsupported operation
107    UnsupportedOperation(String),
108}
109
110impl fmt::Display for ExecutionError {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        match self {
113            ExecutionError::StackUnderflow => write!(f, "Stack underflow"),
114            ExecutionError::StackOverflow => write!(f, "Stack overflow"),
115            ExecutionError::TypeError(msg) => write!(f, "Type error: {}", msg),
116            ExecutionError::RuntimeError(msg) => write!(f, "Runtime error: {}", msg),
117            ExecutionError::MemoryError(msg) => write!(f, "Memory error: {}", msg),
118            ExecutionError::InvalidInstruction(msg) => write!(f, "Invalid instruction: {}", msg),
119            ExecutionError::FunctionError(msg) => write!(f, "Function error: {}", msg),
120            ExecutionError::VariableError(msg) => write!(f, "Variable error: {}", msg),
121            ExecutionError::HeapError(msg) => write!(f, "Heap error: {}", msg),
122            ExecutionError::ControlFlowError(msg) => write!(f, "Control flow error: {}", msg),
123            ExecutionError::BuiltinError(msg) => write!(f, "Built-in error: {}", msg),
124            ExecutionError::DivisionByZero => write!(f, "Division by zero"),
125            ExecutionError::InvalidIndex(idx) => write!(f, "Invalid index: {}", idx),
126            ExecutionError::PropertyNotFound(prop) => write!(f, "Property not found: {}", prop),
127            ExecutionError::MethodNotFound(method) => write!(f, "Method not found: {}", method),
128            ExecutionError::InvalidArgumentCount { expected, received } => {
129                write!(f, "Invalid argument count: expected {}, received {}", expected, received)
130            }
131            ExecutionError::RecursionLimitExceeded(limit) => {
132                write!(f, "Recursion limit exceeded: {}", limit)
133            }
134            ExecutionError::ExecutionTimeout => write!(f, "Execution timeout"),
135            ExecutionError::UnsupportedOperation(op) => write!(f, "Unsupported operation: {}", op),
136        }
137    }
138}
139
140impl Error for ExecutionError {}
141
142impl ExecutionError {
143    /// Creates a new type error with the given message
144    ///
145    /// # Arguments
146    /// * `message` - The error message
147    ///
148    /// # Returns
149    /// * A new `ExecutionError::TypeError`
150    ///
151    /// # Examples
152    ///
153    /// ```rust
154    /// let error = ExecutionError::new_type_error("Cannot add string and number");
155    /// assert!(matches!(error, ExecutionError::TypeError(_)));
156    /// ```
157    pub fn new_type_error(message: impl Into<String>) -> Self {
158        ExecutionError::TypeError(message.into())
159    }
160
161    /// Creates a new runtime error with the given message
162    ///
163    /// # Arguments
164    /// * `message` - The error message
165    ///
166    /// # Returns
167    /// * A new `ExecutionError::RuntimeError`
168    ///
169    /// # Examples
170    ///
171    /// ```rust
172    /// let error = ExecutionError::new_runtime_error("Function execution failed");
173    /// assert!(matches!(error, ExecutionError::RuntimeError(_)));
174    /// ```
175    pub fn new_runtime_error(message: impl Into<String>) -> Self {
176        ExecutionError::RuntimeError(message.into())
177    }
178
179    /// Creates a new memory error with the given message
180    ///
181    /// # Arguments
182    /// * `message` - The error message
183    ///
184    /// # Returns
185    /// * A new `ExecutionError::MemoryError`
186    ///
187    /// # Examples
188    ///
189    /// ```rust
190    /// let error = ExecutionError::new_memory_error("Heap allocation failed");
191    /// assert!(matches!(error, ExecutionError::MemoryError(_)));
192    /// ```
193    pub fn new_memory_error(message: impl Into<String>) -> Self {
194        ExecutionError::MemoryError(message.into())
195    }
196
197    /// Creates a new function error with the given message
198    ///
199    /// # Arguments
200    /// * `message` - The error message
201    ///
202    /// # Returns
203    /// * A new `ExecutionError::FunctionError`
204    ///
205    /// # Examples
206    ///
207    /// ```rust
208    /// let error = ExecutionError::new_function_error("Invalid function call");
209    /// assert!(matches!(error, ExecutionError::FunctionError(_)));
210    /// ```
211    pub fn new_function_error(message: impl Into<String>) -> Self {
212        ExecutionError::FunctionError(message.into())
213    }
214
215    /// Creates a new variable error with the given message
216    ///
217    /// # Arguments
218    /// * `message` - The error message
219    ///
220    /// # Returns
221    /// * A new `ExecutionError::VariableError`
222    ///
223    /// # Examples
224    ///
225    /// ```rust
226    /// let error = ExecutionError::new_variable_error("Variable not defined");
227    /// assert!(matches!(error, ExecutionError::VariableError(_)));
228    /// ```
229    pub fn new_variable_error(message: impl Into<String>) -> Self {
230        ExecutionError::VariableError(message.into())
231    }
232
233    /// Creates a new heap error with the given message
234    ///
235    /// # Arguments
236    /// * `message` - The error message
237    ///
238    /// # Returns
239    /// * A new `ExecutionError::HeapError`
240    ///
241    /// # Examples
242    ///
243    /// ```rust
244    /// let error = ExecutionError::new_heap_error("Garbage collection failed");
245    /// assert!(matches!(error, ExecutionError::HeapError(_)));
246    /// ```
247    pub fn new_heap_error(message: impl Into<String>) -> Self {
248        ExecutionError::HeapError(message.into())
249    }
250
251    /// Creates a new control flow error with the given message
252    ///
253    /// # Arguments
254    /// * `message` - The error message
255    ///
256    /// # Returns
257    /// * A new `ExecutionError::ControlFlowError`
258    ///
259    /// # Examples
260    ///
261    /// ```rust
262    /// let error = ExecutionError::new_control_flow_error("Invalid jump target");
263    /// assert!(matches!(error, ExecutionError::ControlFlowError(_)));
264    /// ```
265    pub fn new_control_flow_error(message: impl Into<String>) -> Self {
266        ExecutionError::ControlFlowError(message.into())
267    }
268
269    /// Creates a new built-in error with the given message
270    ///
271    /// # Arguments
272    /// * `message` - The error message
273    ///
274    /// # Returns
275    /// * A new `ExecutionError::BuiltinError`
276    ///
277    /// # Examples
278    ///
279    /// ```rust
280    /// let error = ExecutionError::new_builtin_error("Console not available");
281    /// assert!(matches!(error, ExecutionError::BuiltinError(_)));
282    /// ```
283    pub fn new_builtin_error(message: impl Into<String>) -> Self {
284        ExecutionError::BuiltinError(message.into())
285    }
286
287    /// Creates a new unsupported operation error with the given message
288    ///
289    /// # Arguments
290    /// * `message` - The error message
291    ///
292    /// # Returns
293    /// * A new `ExecutionError::UnsupportedOperation`
294    ///
295    /// # Examples
296    ///
297    /// ```rust
298    /// let error = ExecutionError::new_unsupported_operation("BigInt operations");
299    /// assert!(matches!(error, ExecutionError::UnsupportedOperation(_)));
300    /// ```
301    pub fn new_unsupported_operation(message: impl Into<String>) -> Self {
302        ExecutionError::UnsupportedOperation(message.into())
303    }
304
305    /// Checks if this error is recoverable
306    ///
307    /// Some errors can be recovered from automatically, while others
308    /// require manual intervention or indicate a serious problem.
309    ///
310    /// # Returns
311    /// * `true` if the error is recoverable
312    /// * `false` if the error requires manual intervention
313    ///
314    /// # Examples
315    ///
316    /// ```rust
317    /// let stack_error = ExecutionError::StackUnderflow;
318    /// assert!(stack_error.is_recoverable());
319    ///
320    /// let type_error = ExecutionError::TypeError("Invalid operation".to_string());
321    /// assert!(!type_error.is_recoverable());
322    /// ```
323    pub fn is_recoverable(&self) -> bool {
324        matches!(
325            self,
326            ExecutionError::StackUnderflow
327                | ExecutionError::StackOverflow
328                | ExecutionError::InvalidIndex(_)
329                | ExecutionError::PropertyNotFound(_)
330                | ExecutionError::MethodNotFound(_)
331        )
332    }
333
334    /// Checks if this error is fatal
335    ///
336    /// Fatal errors cannot be recovered from and typically indicate
337    /// a serious problem with the program or VM state.
338    ///
339    /// # Returns
340    /// * `true` if the error is fatal
341    /// * `false` if the error is not fatal
342    ///
343    /// # Examples
344    ///
345    /// ```rust
346    /// let memory_error = ExecutionError::MemoryError("Heap corruption".to_string());
347    /// assert!(memory_error.is_fatal());
348    ///
349    /// let stack_error = ExecutionError::StackUnderflow;
350    /// assert!(!stack_error.is_fatal());
351    /// ```
352    pub fn is_fatal(&self) -> bool {
353        matches!(
354            self,
355            ExecutionError::MemoryError(_)
356                | ExecutionError::InvalidInstruction(_)
357                | ExecutionError::RecursionLimitExceeded(_)
358                | ExecutionError::ExecutionTimeout
359        )
360    }
361
362    /// Gets a user-friendly error message
363    ///
364    /// Returns a formatted error message suitable for display to users.
365    ///
366    /// # Returns
367    /// * A formatted error message string
368    ///
369    /// # Examples
370    ///
371    /// ```rust
372    /// let error = ExecutionError::TypeError("Cannot add string and number".to_string());
373    /// let message = error.get_user_message();
374    /// assert!(message.contains("Type error"));
375    /// ```
376    pub fn get_user_message(&self) -> String {
377        match self {
378            ExecutionError::StackUnderflow => "Stack is empty".to_string(),
379            ExecutionError::StackOverflow => "Stack is full".to_string(),
380            ExecutionError::TypeError(msg) => format!("Type error: {}", msg),
381            ExecutionError::RuntimeError(msg) => format!("Runtime error: {}", msg),
382            ExecutionError::MemoryError(msg) => format!("Memory error: {}", msg),
383            ExecutionError::InvalidInstruction(msg) => format!("Invalid instruction: {}", msg),
384            ExecutionError::FunctionError(msg) => format!("Function error: {}", msg),
385            ExecutionError::VariableError(msg) => format!("Variable error: {}", msg),
386            ExecutionError::HeapError(msg) => format!("Heap error: {}", msg),
387            ExecutionError::ControlFlowError(msg) => format!("Control flow error: {}", msg),
388            ExecutionError::BuiltinError(msg) => format!("Built-in error: {}", msg),
389            ExecutionError::DivisionByZero => "Division by zero".to_string(),
390            ExecutionError::InvalidIndex(idx) => format!("Invalid index: {}", idx),
391            ExecutionError::PropertyNotFound(prop) => format!("Property not found: '{}'", prop),
392            ExecutionError::MethodNotFound(method) => format!("Method not found: '{}'", method),
393            ExecutionError::InvalidArgumentCount { expected, received } => {
394                format!("Invalid argument count: expected {}, received {}", expected, received)
395            }
396            ExecutionError::RecursionLimitExceeded(limit) => {
397                format!("Recursion limit exceeded: {}", limit)
398            }
399            ExecutionError::ExecutionTimeout => "Execution timeout".to_string(),
400            ExecutionError::UnsupportedOperation(op) => format!("Unsupported operation: {}", op),
401        }
402    }
403
404    /// Gets a debug error message
405    ///
406    /// Returns a detailed error message suitable for debugging and development.
407    ///
408    /// # Returns
409    /// * A detailed debug message string
410    ///
411    /// # Examples
412    ///
413    /// ```rust
414    /// let error = ExecutionError::TypeError("Cannot add string and number".to_string());
415    /// let debug_msg = error.get_debug_message();
416    /// assert!(debug_msg.contains("TypeError"));
417    /// ```
418    pub fn get_debug_message(&self) -> String {
419        format!("{:?}", self)
420    }
421}